package com.uniview.base;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;
import javax.persistence.Id;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Example;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.uniview.entity.vo.Pager;
import com.uniview.entity.vo.QueryBuilder;
import com.uniview.enums.EOrderMode;
import com.uniview.util.HqlUtils;
import com.uniview.util.QueryBuilderUtils;

@Transactional
public class BaseDao<T extends Serializable> {

	@Resource
	protected SessionFactory sessionFactory;

	// 当前泛型类
	@SuppressWarnings("rawtypes")
	private Class entityClass = null;

	// 当前主键名称
	private String pkname = null;
	private String HQL_LIST_ALL = null;
	private String HQL_COUNT_ALL = null;

	private Logger log = Logger.getLogger(BaseDao.class);

	@SuppressWarnings("rawtypes")
	public Class getEntityClass() {
		return entityClass;
	}

	@SuppressWarnings("rawtypes")
	public void setEntityClass(Class entityClass) {
		this.entityClass = entityClass;
	}

	public BaseDao() {
		init();
	}

	public SessionFactory getSessionFactory() {
		return sessionFactory;
	}

	@SuppressWarnings("rawtypes")
	private void init() {
		try {
			// 获取当前泛型类
			Type type = this.getClass().getGenericSuperclass();
			if (type.toString().indexOf("BaseDao") != -1) {
				ParameterizedType type1 = (ParameterizedType) type;
				Type[] types = type1.getActualTypeArguments();
				setEntityClass((Class) types[0]);
			} else {
				type = ((Class) type).getGenericSuperclass();
				ParameterizedType type1 = (ParameterizedType) type;
				Type[] types = type1.getActualTypeArguments();
				setEntityClass((Class) types[0]);
			}
			getPkname();
			HQL_LIST_ALL = "from " + this.entityClass.getSimpleName()
					+ " order by " + pkname + " asc";
			HQL_COUNT_ALL = "select count(*) from "
					+ this.entityClass.getSimpleName();
		} catch (Exception er) {
			log.error("", er);
		}
	}

	/**
	 * 获取主键名称
	 * 
	 * @return
	 */
	public String getPkname() throws Exception {
		Field[] fields = this.entityClass.getDeclaredFields();// 反射类字段
		for (Field field : fields) {
			if (field.isAnnotationPresent(Id.class)) {
				this.pkname = field.getName();
				break;
			}
		}
		return pkname;
	}

	/**
	 * 保存实例
	 * 
	 * @param t
	 * @throws HibernateException
	 */
	@Transactional(propagation = Propagation.REQUIRED)
	public Serializable save(T t) throws Exception {
		if (t != null)
			return sessionFactory.getCurrentSession().save(t);
		return null;
	}
	
	/**
	 * 批量保存实例
	 * @param list
	 * @param batchNum
	 * @return
	 * @throws Exception
	 */
	@Transactional(propagation = Propagation.REQUIRED)
	public boolean save (List<T> list, int batchNum) throws Exception {
		if (!list.isEmpty()) {
			Session session = sessionFactory.getCurrentSession();
	        T t = null;
	        for (int i = 0; i < list.size(); i ++) {
	        	t = list.get(i);
	        	session.save(t);
	        	// 批插入的对象立即写入数据库并释放内存  
	            if (i % batchNum == 0) {  
	                session.flush();  
	                session.clear();  
	            }  
	        }
	        return true;
		}
		return false;
	}
	
	/**
	 * 修改实例
	 * 
	 * @param t
	 * @throws HibernateException
	 */
	@Transactional(propagation = Propagation.REQUIRED)
	public boolean update(T t) throws Exception {
		if (t != null) {
			Session session = sessionFactory.getCurrentSession();
			session.clear();
			session.update(t);
			return true;
		}
		return false;
	}

	/**
	 * 删除实例
	 * 
	 * @param t
	 * @throws HibernateException
	 */
	@Transactional(propagation = Propagation.REQUIRED)
	public boolean delete(T t) throws Exception {
		if (t != null) {
			sessionFactory.getCurrentSession().delete(t);
			return true;
		}
		return false;
	}

	/**
	 * 根据主键ID,删除实例
	 * 
	 * @param id
	 * @return
	 * @throws Exception
	 */
	@Transactional(propagation = Propagation.REQUIRED)
	public boolean deleteById(Serializable id) throws Exception {
		T t = this.find(id);
		if (t != null) {
			return this.delete(t);
		}
		return false;
	}

	/**
	 * 获取实例
	 * 
	 * @param id
	 * @throws HibernateException
	 */
	@Transactional(propagation = Propagation.REQUIRED)
	@SuppressWarnings("unchecked")
	public T find(Serializable id) throws Exception {
		if (id != null) {
			return (T) sessionFactory.getCurrentSession().get(getEntityClass(),
					id);
		}
		return null;
	}

	/**
	 * 查询全部
	 * 
	 * @throws HibernateException
	 */
	@SuppressWarnings("unchecked")
	@Transactional(propagation = Propagation.REQUIRED)
	public List<T> findAll() throws Exception {
		Query query = sessionFactory.getCurrentSession().createQuery(
				HQL_LIST_ALL);
		if (query != null)
			return query.list();
		return null;
	}

	/**
	 * 查询总数
	 * 
	 * @throws HibernateException
	 */
	@Transactional(propagation = Propagation.REQUIRED)
	public Long findTotalRow() throws Exception {
		Query query = sessionFactory.getCurrentSession().createQuery(
				HQL_COUNT_ALL);
		if (query != null) {
			List<?> list = query.list();
			if (list != null && !list.isEmpty()) {
				return (Long)(list.get(0));
			}
		}
		return null;
	}

	/**
	 * 按条件查询总记录数
	 * 
	 * @param countHql
	 * @param map
	 * @return
	 * @throws Exception
	 */
	@Transactional(propagation = Propagation.REQUIRED)
	public Integer findTotalRow(String countHql, final Object... objects)
			throws Exception {
		if (StringUtils.isNotBlank(countHql)) {
			Query query = sessionFactory.getCurrentSession().createQuery(
					countHql);
			if (query != null) {
				if (objects != null) {
					for (int i = 0; i < objects.length; i++) {
						query.setParameter(i, objects[i]);
					}
				}
				return Integer.valueOf(query.list().get(0) + "");
			}
		}
		return null;
	}
	
	/**
	 * 按条件查询总记录数
	 * 
	 * @param countHql
	 * @param map
	 * @return
	 * @throws Exception
	 */
	@Transactional(propagation = Propagation.REQUIRED)
	public Integer findTotalRowBySql(String countSql, final Object... objects)
			throws Exception {
		if (StringUtils.isNotBlank(countSql)) {
			Query query = sessionFactory.getCurrentSession().createSQLQuery(countSql);
			if (query != null) {
				if (objects != null) {
					for (int i = 0; i < objects.length; i++) {
						query.setParameter(i, objects[i]);
					}
				}
				return Integer.valueOf(query.list().get(0) + "");
			}
		}
		return null;
	}

	/**
	 * 按条件查询总记录数
	 * 
	 * @param countHql
	 * @param params
	 * @return
	 * @throws Exception
	 */
	@Transactional(propagation = Propagation.REQUIRED)
	public Integer findTotalRow(String countHql,
			final Map<String, Object> params) throws Exception {
		if (StringUtils.isNotBlank(countHql)) {
			Query query = sessionFactory.getCurrentSession().createQuery(
					countHql);
			if (query != null) {
				if (params != null && params.keySet() != null) {
					for (String colName : params.keySet()) {
						if(colName.equals("id")){
							 Object obj = params.get(colName);
			                //这里考虑传入的参数是什么类型，不同类型使用的方法不同  
			                if(obj instanceof Collection<?>){  
			                    query.setParameterList(colName, (Collection<Long>)obj);  
			                }else if(obj instanceof Object[]){  
			                	Object[] ids = (Object[]) obj;
			                	List<Long> list = new ArrayList<Long>();
			                	for(Object id : ids){
			                		System.err.println(Long.valueOf(id.toString())+"---");
			                		list.add(Long.valueOf(id.toString()));
			                	}
			                    query.setParameterList(colName, list);  
			                }else{  
			                    query.setParameter(colName, (Long)obj);  
			                }  
						}else
							query.setParameter(colName, params.get(colName));
					}
				}
				return Integer.valueOf(query.list().get(0) + "");
			}
		}
		return null;
	}

	/**
	 * QBC查询
	 * 
	 * @param criteria
	 * @throws HibernateException
	 */
	@SuppressWarnings("unchecked")
	@Transactional(propagation = Propagation.REQUIRED)
	public List<T> findByCriteria(Criteria criteria) throws Exception {
		if (criteria != null) {
			Criteria ct = sessionFactory.getCurrentSession().createCriteria(
					getEntityClass());
			return ct.list();
		}
		return null;
	}

	/**
	 * QBE查询
	 * 
	 * @param t
	 * @throws HibernateException
	 */
	@SuppressWarnings("unchecked")
	@Transactional(propagation = Propagation.REQUIRED)
	public List<T> findByExample(T t) throws Exception {
		if (t != null) {
			Example example = Example.create(t);
			Criteria criteria = sessionFactory.getCurrentSession()
					.createCriteria(getEntityClass());
			criteria.add(example);
			return criteria.list();
		}
		return null;
	}

	/**
	 * HQL查询
	 * 
	 * @param hql
	 * @param objects
	 * @throws HibernateException
	 */
	@SuppressWarnings("unchecked")
	@Transactional(propagation = Propagation.REQUIRED)
	public List<T> findByHql(String hql, final Object... objects)
			throws Exception {
		if (StringUtils.isNotBlank(hql)) {
			Query query = sessionFactory.getCurrentSession().createQuery(hql);
			if (query != null) {
				for (int i = 0; i < objects.length; i++) {
					query.setParameter(i, objects[i]);
				}
				return (List<T>) query.list();
			}
		}
		return null;
	}

	/**
	 * HQL查询
	 * 
	 * @param hql
	 * @param params
	 * @return
	 */
	@SuppressWarnings("unchecked")
	@Transactional(propagation = Propagation.REQUIRED)
	public List<T> findByHql(String hql, final Map<String, Object> params) {
		if (StringUtils.isNotBlank(hql)) {
			Query query = sessionFactory.getCurrentSession().createQuery(hql);
			if (query != null) {
				if (params != null && params.keySet() != null) {
					for (String colName : params.keySet()) {
						query.setParameter(colName, params.get(colName));
					}
				}
				return (List<T>) query.list();
			}
		}
		return null;
	}

	/**
	 * SQL查询
	 * 
	 * @param hql
	 * @param objects
	 * @throws HibernateException
	 */
	@SuppressWarnings("unchecked")
	@Transactional(propagation = Propagation.REQUIRED)
	public List<T> findBySql(String sql, final Object... objects)
			throws Exception {
		if (StringUtils.isNotBlank(sql)) {
			Query query = sessionFactory.getCurrentSession()
					.createSQLQuery(sql).addEntity(getEntityClass());
			if (query != null) {
				for (int i = 0; i < objects.length; i++) {
					query.setParameter(i, objects[i]);
				}
				return (List<T>) query.list();
			}
		}
		return null;
	}

	/**
	 * SQL查询
	 * 
	 * @param hql
	 * @param objects
	 * @throws HibernateException
	 */
	@SuppressWarnings("unchecked")
	@Transactional(propagation = Propagation.REQUIRED)
	public List<T> findBySql(String sql, final Map<String, Object> params)
			throws Exception {
		if (StringUtils.isNotBlank(sql)) {
			Query query = sessionFactory.getCurrentSession()
					.createSQLQuery(sql).addEntity(getEntityClass());
			if (query != null) {
				if (params != null && params.keySet() != null) {
					for (String colName : params.keySet()) {
						query.setParameter(colName, params.get(colName));
					}
				}

				return (List<T>) query.list();
			}
		}
		return null;
	}
	
	/**
	 * SQL查询
	 * 
	 * @param hql
	 * @param objects
	 * @throws HibernateException
	 */
	@SuppressWarnings("unchecked")
	@Transactional(propagation = Propagation.REQUIRED)
	public List<T> findPagerBySql(String sql,int pageNo,int pageSize, final Object... objects)
			throws Exception {
		if (StringUtils.isNotBlank(sql)) {
			Query query = sessionFactory.getCurrentSession()
					.createSQLQuery(sql).addEntity(getEntityClass());
			if (query != null) {
				for (int i = 0; i < objects.length; i++) {
					// 赋值查询字段的值
					query.setParameter(i, objects[i]);
				}
				query.setFirstResult((pageNo - 1) * pageSize);
				query.setMaxResults(pageSize);
				return (List<T>) query.list();
			}
		}
		return null;
	}

	/**
	 * HQL更新
	 * 
	 * @param hql
	 * @param objects
	 * @return
	 * @throws Exception
	 */
	@Transactional(propagation = Propagation.REQUIRED)
	public boolean updateByHql(String hql, final Object... objects)
			throws Exception {
		if (StringUtils.isNotBlank(hql)) {
			Query query = sessionFactory.getCurrentSession().createQuery(hql);
			for (int i = 0; i < objects.length; i++) {
				// 赋值查询字段的值
				query.setParameter(i, objects[i]);
			}
			return query.executeUpdate() > 0;
		}
		return false;
	}

	/**
	 * HQL更新
	 * 
	 * @param hql
	 * @param objects
	 * @return
	 * @throws Exception
	 */
	@Transactional(propagation = Propagation.REQUIRED)
	public boolean deleteByHql(String hql, final Object... objects)
			throws Exception {
		if (StringUtils.isNotBlank(hql)) {
			Query query = sessionFactory.getCurrentSession().createQuery(hql);
			for (int i = 0; i < objects.length; i++) {
				// 赋值查询字段的值
				query.setParameter(i, objects[i]);
			}
			return query.executeUpdate() > 0;
		}
		return false;
	}

	/**
	 * 按条件，分页查询记录集
	 * 
	 * @param pageNo
	 * @param pageSize
	 * @param hql
	 * @param map
	 * @return 返回Pager
	 * @throws Exception
	 */
	@SuppressWarnings("unchecked")
	@Transactional(propagation = Propagation.REQUIRED)
	public Pager<T> findPagerByQuery(int pageNo, int pageSize, String hql,
			final Object... objects) throws Exception {
		Pager<T> pager = new Pager<T>();
		if (StringUtils.isNotBlank(hql)) {
			Query query = sessionFactory.getCurrentSession().createQuery(hql);
			for (int i = 0; i < objects.length; i++) {
				// 赋值查询字段的值
				query.setParameter(i, objects[i]);
			}
			query.setFirstResult((pageNo - 1) * pageSize);
			query.setMaxResults(pageSize);
			List<T> list = (List<T>) query.list();
			// 分页记录集
			pager.setPagerList(list);
			Integer totalRow = findTotalRow(HqlUtils.buildCountHQL(hql),
					objects);
			// 记录总行数
			pager.setTotalRow(totalRow);
		}
		return pager;
	}

	/**
	 * 按条件，分页查询记录集
	 * 
	 * @param pageNo
	 * @param pageSize
	 * @param hql
	 *            HQL查询语句
	 * @param params
	 *            查询参数Map<字段名，字段值>
	 * @return
	 * @throws Exception
	 */
	@SuppressWarnings("unchecked")
	@Transactional(propagation = Propagation.REQUIRED)
	public Pager<T> findPagerByQuery(int pageNo, int pageSize, String hql,
			final Map<String, Object> params, EOrderMode orderMode,
			String... orderCols) throws Exception {
		Pager<T> pager = new Pager<T>();
		if (StringUtils.isNotBlank(hql)) {
			// 循环Map中的key作为查询字段, 拼装成查询语句
			hql = HqlUtils.buildOrderHQL(hql, orderMode, orderCols);
			Query query = sessionFactory.getCurrentSession().createQuery(hql);
			if (params != null && params.keySet() != null) {
				for (String colName : params.keySet()) {
					query.setParameter(colName, params.get(colName));
				}
			}
			query.setFirstResult((pageNo - 1) * pageSize);
			query.setMaxResults(pageSize);
			List<T> list = (List<T>) query.list();
			// 分页记录集
			pager.setPagerList(list);
			Integer totalRow = findTotalRow(HqlUtils.buildCountHQL(hql), params);
			// 记录总行数
			pager.setTotalRow(totalRow);
		}
		return pager;
	}

	/**
	 * 按条件，分页查询记录集
	 * 
	 * @param pageNo
	 * @param pageSize
	 * @param hql
	 * @param params
	 * @return
	 * @throws Exception
	 */
	@SuppressWarnings("unchecked")
	@Transactional(propagation = Propagation.REQUIRED)
	public Pager<T> findPagerByQuery(int pageNo, int pageSize, String hql,
			final Map<String, Object> params) throws Exception {
		Pager<T> pager = new Pager<T>();
		if (StringUtils.isNotBlank(hql)) {
			Query query = sessionFactory.getCurrentSession().createQuery(hql);
			if (params != null && params.keySet() != null) {
				for (String colName : params.keySet()) {
					query.setParameter(colName, params.get(colName));
				}
			}
			query.setFirstResult((pageNo - 1) * pageSize);
			query.setMaxResults(pageSize);
			List<T> list = (List<T>) query.list();
			// 分页记录集
			pager.setPagerList(list);
			Integer totalRow = findTotalRow(HqlUtils.buildCountHQL(hql), params);
			// 记录总行数
			pager.setTotalRow(totalRow);
		}
		return pager;
	}

	/**
	 * 根据QueryBuilder进行条件查询
	 * 
	 * @param queryBuilder
	 * @return
	 * @throws Exception
	 */
	@SuppressWarnings("unchecked")
	@Transactional(propagation = Propagation.REQUIRED)
	public List<T> findListByQueryBuilder(QueryBuilder queryBuilder)
			throws Exception {
		if (queryBuilder != null) {
			QueryBuilderUtils qBuilderUtils = new QueryBuilderUtils();
			// 生成HQL查询语句
			String hql = qBuilderUtils.builderHQL(queryBuilder);
			log.debug(hql);
			Query query = sessionFactory.getCurrentSession().createQuery(hql);
			// 获取查询参数
			Map<String, Object> params = qBuilderUtils.getParamsMap();
			if (params != null && params.keySet() != null) {
				for (String colName : params.keySet()) {
					query.setParameter(colName, params.get(colName));
				}
			}
			return query.list();
		}
		return null;
	}

	/**
	 * 根据QueryBuilder组装查询语句，获取分页查询的结果
	 * 
	 * @param pageNo
	 * @param pageSize
	 * @param queryBuilder
	 * @param params
	 * @return
	 * @throws Exception
	 */
	@SuppressWarnings("unchecked")
	@Transactional(propagation = Propagation.REQUIRED)
	public Pager<T> findPagerByQueryBuilder(QueryBuilder queryBuilder,
			int pageNo, int pageSize) throws Exception {
		Pager<T> pager = new Pager<T>();
		if (queryBuilder != null) {
			String hql = null;
			Map<String, Object> params = null;
			QueryBuilderUtils qBuilderUtils = new QueryBuilderUtils();
			// 生成HQL查询语句
			hql = qBuilderUtils.builderHQL(queryBuilder);
			log.debug(hql);
			Query query = sessionFactory.getCurrentSession().createQuery(hql);
			// 获取查询参数
			params = qBuilderUtils.getParamsMap();
			if (params != null && params.keySet() != null) {
				for (String colName : params.keySet()) {
					if(colName.equals("id")){
						 Object obj = params.get(colName);
		                //这里考虑传入的参数是什么类型，不同类型使用的方法不同  
		                if(obj instanceof Collection<?>){  
		                    query.setParameterList(colName, (Collection<Long>)obj);  
		                }else if(obj instanceof Object[]){  
		                	Object[] ids = (Object[]) obj;
		                	List<Long> list = new ArrayList<Long>();
		                	for(Object id : ids){
		                		System.err.println(Long.valueOf(id.toString())+"---");
		                		list.add(Long.valueOf(id.toString()));
		                	}
		                    query.setParameterList(colName, list);  
		                }else{  
		                    query.setParameter(colName, (Long)obj);  
		                }  
					}else
						query.setParameter(colName, params.get(colName));
				}
			}
			query.setFirstResult((pageNo - 1) * pageSize);
			query.setMaxResults(pageSize);
			List<T> list = (List<T>) query.list();
			// 分页记录集
			pager.setPagerList(list);

			Integer totalRow = findTotalRow(HqlUtils.buildCountHQL(hql), params);
			// 记录总行数
			pager.setTotalRow(totalRow);
		}
		return pager;
	}

	public void setSessionFactory(SessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
	}
	
}
